﻿#region

using System;
using System.Collections.Generic;
using System.IO;

using System.Xml;
using System.Xml.Serialization;

using MessageTypeDescriber.Xml.Members;

#endregion

namespace MessageTypeDescriber.Xml
{
    [Serializable]
    public class TypeFullDescription : TypeDescription, IEquatable<TypeFullDescription>
    {
        public List<MemberDescription> Elements { get; set; }
        public List<TypeDescription> Interfaces { get; set; }
        public TypeDescription BaseType { get; set; }

        protected TypeFullDescription()
        {
        }

        public TypeFullDescription(Type type)
            : base(type)
        {
            if (type.BaseType != null)
            {
                BaseType = new TypeDescription(type.BaseType);
            }

            Interfaces = new List<TypeDescription>();

            foreach (var @interface in type.GetInterfaces())
            {
                Interfaces.Add(new TypeDescription(@interface));
            }

            Elements = new List<MemberDescription>();

            foreach (var method in type.GetMethods())
            {
                if (!method.IsSpecialName)
                {
                    Elements.Add(new MethodDescription(method));
                }
            }

            foreach (var property in type.GetProperties())
            {
                Elements.Add(new PropertyDescription(property));
            }

            foreach (var field in type.GetFields())
            {
                Elements.Add(new FieldDescription(field));
            }
                     
        }


        private static readonly XmlSerializer Serializer;

        static TypeFullDescription()
        {
            Serializer = new XmlSerializer(typeof (TypeFullDescription), new[]
                                                                              {
                                                                                  typeof (MethodDescription),
                                                                                  typeof (MemberDescription),
                                                                                  typeof (TypeDescription),
                                                                                  typeof (FieldDescription),
                                                                                  typeof (PropertyDescription)
                                                                              });
        }

        public static string ToXml(TypeFullDescription typeFullDescription)
        {
            StringWriter writer = new StringWriter();
            Serializer.Serialize(writer, typeFullDescription);

            var xml = writer.ToString();

            return xml;
        }

        public static TypeFullDescription FromXml(string xml)
        {
            StringReader read = new StringReader(xml);
            XmlReader reader = new XmlTextReader(read);

            TypeFullDescription typeFullDescription = (TypeFullDescription) Serializer.Deserialize(reader);

            return typeFullDescription;
        }


        public bool Equals(TypeFullDescription other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }
            return Equals(other.Elements, Elements) && Equals(other.Interfaces, Interfaces) && Equals(other.BaseType, BaseType);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != typeof (TypeFullDescription))
            {
                return false;
            }
            return Equals((TypeFullDescription) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = (Elements != null ? Elements.GetHashCode() : 0);
                result = (result*397) ^ (Interfaces != null ? Interfaces.GetHashCode() : 0);
                result = (result*397) ^ (BaseType != null ? BaseType.GetHashCode() : 0);
                return result;
            }
        }

        public static bool operator ==(TypeFullDescription left, TypeFullDescription right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(TypeFullDescription left, TypeFullDescription right)
        {
            return !Equals(left, right);
        }
    }
}

